/*
 * AppConfig.h
 *
 *  Created on: 2010-03-30
 *      Author: kamil
 */

#ifndef CONFIG_H_
#define CONFIG_H_

#include <boost/program_options.hpp>
#include <iostream>
#include <fstream>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <list>
#include "mgr/id/ModelId.h"
#include "mgr/util/Vector2d.h"
#include "mgr/util/Rect.h"
#include "mgr/util/types.h"


/**
 * Parser app config files and provides easy access to data from
 * any point in the application code (singleton).
 */
class Config {
public:
	/**
	 * Class storing info about the ball
	 */
	struct BallInfo{
		std::string name;
		double radius;
		ModelId id;

		friend std::ostream & operator<<(std::ostream &, const BallInfo &);
	};

	struct RobotInfo{
		double radius;
		double kickingForce;
		double passingForce;

		friend std::ostream & operator<<(std::ostream &, const RobotInfo &);
	};

	struct RRTInfo{
		double safetyMargin;
		int maxNodes;

		friend std::ostream & operator<<(std::ostream &, const RRTInfo &);
	};

	struct PredictionInfo{
		int steps;
		double time;

		friend std::ostream & operator<<(std::ostream &, const PredictionInfo &);
	};

	struct FieldInfo{
		Rect fieldArea;
		Rect gameArea;
		Vector2d center;
		Vector2d firstGoal;
		Vector2d secondGoal;
		double goalWidth;
		double centerCircleRadius;

		Vector2d getGoalPosition(GoalId id) const;
		friend std::ostream & operator<<(std::ostream &, const FieldInfo &);
	};

	struct PidInfo{
		double k, ti, td;

		friend std::ostream & operator<<(std::ostream &, const PidInfo &);
	};

	struct VideoInfo{
		double updateRate;	//in seconds

		friend std::ostream & operator<<(std::ostream &, const VideoInfo &);
	};

public:
	static Config & instance();
	~Config();

/////////////////////// public methods ////////////////////////
public:
	void parse(std::string fileName);

	////// static getters to skip ::instance() call	//////
	static BallInfo getBallInfo() { return instance().ballInfo; }
	static RobotInfo getRobotInfo() { return instance().robotInfo; }
	static FieldInfo getFieldInfo() { return instance().fieldInfo; }
	static RRTInfo getRRTInfo() { return instance().rrtInfo; }
	static PredictionInfo getPredictionInfo() { return instance().predictionInfo; }
	static PidInfo getRotationPidInfo() { return instance().rotationPidInfo; }
	static PidInfo getPositionPidInfo() { return instance().positionPidInfo; }
	static VideoInfo getVideoInfo() {return instance().videoInfo; }


/*	ModelId ballId();

	std::string ball();
	double ballRadius();

	double safetyMargin();
	int maxNodes();

	int predictionSteps();
	double predictionTime();*/

	TeamName getTeamName(const ModelId & id);

	void getTeammates(const ModelId & id, std::list<ModelId> * teammates);

	/// Fills given team list with ids of models belonging to given team
	void getTeam(const TeamName & teamName, std::list<ModelId> * team);

	/// Number of all robots in the team
	int getTeamSize();

////////////////////////// private methods ////////////////////
private:
	Config();
	Config(const Config &);

	/**
	 * According to read _team1 and _team2 vectors, it prepares map
	 * robotname (str)- TeamName (enum)
	 */
	void prepareTeamMap(const std::string & teamBlue,const std::string & teamYellow);

///////////////////// config fields ///////////////////////////
private:
	BallInfo ballInfo;
	RobotInfo robotInfo;
	RRTInfo rrtInfo;
	PredictionInfo predictionInfo;
	FieldInfo fieldInfo;
	PidInfo rotationPidInfo;
	PidInfo positionPidInfo;
	VideoInfo videoInfo;

/*
	std::string _videoserverIP;
	int _videoserverPort;

	ModelId _robotId;*/

	//...... team name map .......
	std::map<ModelId, TeamName> _teamMap;

	//teams
	std::set<ModelId> _teamBlue;
	std::set<ModelId> _teamYellow;
};

#endif /* APPCONFIG_H_ */
